package com.invengo.device;

import android.annotation.SuppressLint;
import android.app.Application;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import androidx.annotation.NonNull;

import com.invengo.library_rfid.VoiceManager;
import com.invengo.library_rfid.analyze.EPCAnalyzeFactory;
import com.invengo.library_rfid.analyze.EPCStrategy;
import com.invengo.library_rfid.analyze._EpcRuleTag;
import com.invengo.library_rfid.classify.AnalyzeImpl;
import com.invengo.library_rfid.classify.RfidModelImpl;
import com.invengo.library_rfid.device.IDevice;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import invengo.javaapi.core.BaseReader;
import invengo.javaapi.core.IMessageNotification;
import invengo.javaapi.core.Util;
import invengo.javaapi.handle.IMessageNotificationReceivedHandle;
import invengo.javaapi.protocol.IRP1.IntegrateReaderManager;
import invengo.javaapi.protocol.IRP1.PowerOff;
import invengo.javaapi.protocol.IRP1.RXD_TagData;
import invengo.javaapi.protocol.IRP1.ReadTag;
import invengo.javaapi.protocol.IRP1.Reader;
import invengo.javaapi.protocol.IRP1.SysConfig_800;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import java8.util.Optional;
import me.goldze.mvvmhabit.bus.RxBus;
import me.goldze.mvvmhabit.bus.RxSubscriptions;
import me.goldze.mvvmhabit.http.interceptor.logging.LocalLogUtil;
import me.goldze.mvvmhabit.utils.KLog;
import me.goldze.mvvmhabit.utils.ToastUtils;
import me.goldze.mvvmhabit.utils.cache.ACache;
import me.goldze.mvvmhabit.utils.cache.AKey;

public class DeviceHelper implements IDevice, IMessageNotificationReceivedHandle {

    protected Reader mReader;
    private AnalyzeImpl analyze = AnalyzeImpl.TO_BOOK; //解析类型，比如book，shelf，tid
    private EPCStrategy strategy; //标签解析方案
    private RfidModelImpl rfidModel;//标签类型更改
    private boolean isOpenVoice = true;//声音是否打开

    public static DeviceHelper instance;
    protected ExecutorService mThreadService;

    private VoiceManager voiceManager;

    public static DeviceHelper getInstance() {
        if (instance == null) synchronized (DeviceHelper.class) {
            if (instance == null) {
                instance = new DeviceHelper();
            }
        }
        return instance;
    }

    public VoiceManager getVoiceManager() {
        return voiceManager;
    }

    private DeviceHelper() {
        rfidModel = RfidModelImpl.getDefaultModel();
        strategy = EPCAnalyzeFactory.getInstance().getRuleStrategy();
        System.out.println("设置默认模型及标签：[ "+ strategy.getRule().getRuleName()+" ]  [ "+ rfidModel.name()+" ]");

//        rfidModel = RfidModelImpl.values()[Optional.ofNullable((Integer) ACache.getInstance().getAsObject(AKey.RFIDMODEL_POSITION)).orElse(0)];
//        strategy = EPCAnalyzeFactory.getInstance().getEPCStrategy(_EpcRuleTag.values()[Optional.ofNullable((Integer) ACache.getInstance().getAsObject(AKey.RFIDRULE_POSITION)).orElse(0)]);
        isOpenVoice = ACache.getInstance().getAsBoolean(AKey.IS_OPEN_VOICE);
        mThreadService = Executors.newCachedThreadPool();
    }

    @Override
    public void init(Application application) {
        voiceManager = VoiceManager.getInstance(application);
        RxSubscriptions.add(RxBus.getDefault().toObservable(_EpcRuleTag.class).subscribe(ruleTag -> {
            Log.w(getClass().getSimpleName(), "切换解析 模型 >>>： " + ruleTag.getRuleName());
            this.strategy = EPCAnalyzeFactory.getInstance().getEPCStrategy(ruleTag);
        }));
        RxSubscriptions.add(RxBus.getDefault().toObservable(AnalyzeImpl.class).subscribe(analyzeModel -> {
            Log.w(getClass().getSimpleName(), "切换解析 类型 >>>： " + analyzeModel.getName());
            this.analyze = analyzeModel;
        }));
        RxSubscriptions.add(RxBus.getDefault().toObservable(RfidModelImpl.class).subscribe(rfidModel -> {
            Log.w(getClass().getSimpleName(), "切换标签 类型 >>>： " + rfidModel.getName());
            this.rfidModel = rfidModel;
        }));
        openDevice();
    }

    @Override
    public void openDevice() {
        checkInterval();
        String ip = IntegrateReaderManager.getPortName();
        mThreadService.execute(() -> {
            String address = ip + ",115200";
            if (mReader == null) {
                mReader = new Reader("readerName", "RS232", address);
                try {
                    boolean isConnect = mReader.connect();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private Disposable connectInterval;

    private void checkInterval() {
        if (connectInterval == null)
            connectInterval = Observable.interval(5000, TimeUnit.MILLISECONDS)
                    .subscribeOn(AndroidSchedulers.mainThread())
                    .subscribe(aLong -> {
//                        KLog.e("每隔5秒检查一下"+aLong);
                        RxBus.getDefault().post(checkReaderConnection());
                    });
    }

    @Override
    public void closeDevice() {
        mThreadService.execute(() -> {
            if (mReader != null && mReader.isConnected()) {
                mReader.onMessageNotificationReceived.remove(this);
                mReader.disConnect();
            }
        });
        if (connectInterval != null && !connectInterval.isDisposed())
            connectInterval.dispose();
    }

    private String cacheKey;
    protected boolean isReading = false;


    @Override
    public void startScan(String cacheKey) {
        this.cacheKey = cacheKey;
        List<String> strings = Optional.ofNullable(analyze.cache.get(cacheKey)).orElseGet(ArrayList::new);
        analyze.cache.put(cacheKey, strings);
        if (!isReading)
            mThreadService.execute(() -> {
                if (!checkReaderConnection()) {
                    RxBus.getDefault().post(false);
                    KLog.e("设备链接失败");
                    return;
                }
                mReader.onMessageNotificationReceived.add(this);
                ReadTag.ReadMemoryBank memoryBank= rfidModel==RfidModelImpl.TID?ReadTag.ReadMemoryBank.TID_6C:ReadTag.ReadMemoryBank.EPC_6C;
                ReadTag readTag = new ReadTag(memoryBank);
                isReading = mReader.send(readTag);
            });
    }

    @Override
    public void stopScan() {
        if (isReading)
            mThreadService.execute(() -> {
                List<String> strings = Optional.ofNullable(analyze.cache.get(cacheKey)).orElseGet(ArrayList::new);
                System.out.println("执行停止   当前缓存[" + cacheKey + "] ==》" + strings);
                if (mReader != null) {
                    isReading = false;
                    mReader.onMessageNotificationReceived.remove(this);
                    mReader.send(new PowerOff());
                    mReader.send(new PowerOff());
                }
            });
    }

    @Override
    public boolean checkReaderConnection() {
        if (mReader == null) {
            Log.e(getClass().getSimpleName(), "设备未连接");
            return false;
        }
        return mReader.isConnected();
    }

    @Override
    public void changeAnalyzeModel(AnalyzeImpl analyzeModel) {
        this.analyze = analyzeModel;
    }

    @Override
    public void cleanCache(String cacheKey) {
        Optional.ofNullable(analyze.cache.get(cacheKey)).ifPresent(list -> {
            System.out.println("取消第2-1步：清理[ " + cacheKey + " ] 缓存" + list.size());
            list.clear();
            System.out.println("取消第2-2步：清理后的缓存 [ " + cacheKey + " ] 缓存" + list.size());
        });
    }


    public void addTempCache(String cacheKey) {
        this.cacheKey = cacheKey;
        List<String> strings = Optional.ofNullable(analyze.cache.get(cacheKey)).orElseGet(ArrayList::new);
        System.out.println("当前缓存[" + cacheKey + "] ==》" + strings);
        analyze.cache.put(cacheKey, strings);
    }

    public List<String> getCache(String cacheKey) {
        return analyze.cache.get(cacheKey);
    }

    @Override
    public boolean isReading() {
        return isReading;
    }

    @Override
    public int[] getPowerMeter() {
        if (!checkReaderConnection()) {
            Log.e(getClass().getSimpleName(), "设备链接失败");
            return null;
        }
        return null;
    }

    public void changePower(int integer) {
        mThreadService.execute(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stopScan();
            if (!checkReaderConnection()) {
                Log.e(getClass().getSimpleName(), "Reader is disconnected");
                return;
            }
            mReader.send(new PowerOff());
            byte[] data = new byte[]{(byte) 2, (byte) 0, (byte) integer};
            SysConfig_800 sysConfig_800 = new SysConfig_800((byte) 0x65, data);
            Message msg = new Message();
            if (!mReader.send(sysConfig_800)) {
                msg.obj= false;
//                ToastUtils.showShort("设置功率失败");
                LocalLogUtil.device2Log("设置功率失败：" + integer);
            } else {
                msg.obj= true;
//                ToastUtils.showShort("设置功率成功");
                LocalLogUtil.device2Log("设置功率成功" + integer);
                ACache.getInstance().put(AKey.RFID_POWER, integer);
            }
            Looper.prepare();
            handler.handleMessage(msg);
            Looper.loop();
        });
    }
    Handler handler =new Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(@NonNull Message msg) {
            KLog.e((Boolean) msg.obj?"设置功率成功":"设置功率失败");
            if ((Boolean) msg.obj){
                ToastUtils.showShort("设置功率成功");
            }else{
                ToastUtils.showShort("设置功率失败");
            }
        }
    };


    @Override
    public int[] getPower() {
        if (!checkReaderConnection()) {
            Log.e(getClass().getSimpleName(), "设备链接失败");
            return null;
        }
        return null;
    }

    @Override
    public List<String> getDeviceList() {
        return new ArrayList<>();
    }

    @Override
    public void changeVoice(boolean needVoice) {
        ACache.getInstance().put(AKey.IS_OPEN_VOICE, needVoice);
        if (needVoice) {
            DeviceHelper.getInstance().getVoiceManager().playBeep();
        }
        isOpenVoice = needVoice;
    }

    @Override
    public void playVoice() {
        if (isOpenVoice)
            DeviceHelper.getInstance().getVoiceManager().playSuccessSound();
    }
    @Override
    public void playOhterVoice() {
        if (isOpenVoice)
            DeviceHelper.getInstance().getVoiceManager().playFailureSound();
    }
    @Override
    public void messageNotificationReceivedHandle(BaseReader baseReader, IMessageNotification iMessageNotification) {
        String tid = "";
        String epc = "";
        if (iMessageNotification instanceof RXD_TagData) {
            RXD_TagData data = (RXD_TagData) iMessageNotification;
            epc = Util.convertByteArrayToHexString(data.getReceivedMessage().getEPC());
            tid = Util.convertByteArrayToHexString(data.getReceivedMessage().getTID());
        }
        if (rfidModel == RfidModelImpl.TID) {
            analyze.apply(tid, epc, rfidModel, strategy, cacheKey);
        } else if (rfidModel == RfidModelImpl.EPC) {
            analyze.apply(tid, epc, rfidModel, strategy, cacheKey);
        } else {
        }
    }
}
